//==============================================================================
//
//    DCRC32 - the cyclic redundancy check class in the ofc-library
//
//               Copyright (C) 2005  Dick van Oudheusden
//  
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 3 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free
// Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
//
//==============================================================================
// 
//  $Date: 2008-08-26 05:50:30 $ $Revision: 1.6 $
//==============================================================================

#include "ofc/DCRC32.h"


#if _INTERFACE_

#include <stdint.h>

#include "ofc/config.h"
//
// The CRC32 class implements a number of methods for calculating the CRC-32
// checksum.
//
// @example
//
// #include <stdio.h>
// #include "ofc/DCRC32.h"
// 
// int main(int argc, char *argv[])
// {
//   DCRC32 *crc = [DCRC32 new];
// 
//   [crc update :"This is an example for the CRC32 class"];  // Feed the CRC32 with a c-string
// 
//   [crc update :"This is data\0With string terminator" :35]; // Feed the CRC32 with data
// 
//   printf("CRC32 value: %lx.\n", [crc crc32]);              // Get the CRC32 value
// 
//   [crc free];                                              // Cleanup
// 
//   return 0;
// }
// 

@interface DCRC32 : DObject
{
@private
  uint32_t _crc32;    // the crc32 value
}

#endif



@implementation DCRC32

#if _PRIVATE_
static uint32_t *_table = NULL;

static void _buildCrc32Table()
{
  if (_table == NULL)
  {
    uint32_t crc;
    uint32_t poly;
    int      i;
    int      j;
    
    _table = (uint32_t *) objc_malloc(sizeof(uint32_t) * 256);

    poly = 0xEDB88320;
    
    for (i = 0; i < 256; i++)
    {
      crc = i;
      
      for (j = 8; j > 0; j--)
      {
        if (crc & 1)
        {
          crc = (crc >> 1) ^ poly;
        }
        else
        {
          crc >>= 1;
        }
      }
      
      _table[i] = crc;
    }
  }
}
#endif


//// Constructors

//
// Initialise to an empty object
//
// @return the instance
//

- (DCRC32 *) init
{
  [super init];

  _buildCrc32Table();
  
  _crc32 = 0xFFFFFFFF;

  return self;
}

//
// Initialise the object with a c-string
//
// @param cstring  the string
//
// @return the object
//

- (DCRC32 *) init :(const char *) cstring
{
  [self init];

  [self update :cstring];
  
  return self;
}

//
// Initialise the object with data
//
// @param data     the data ('\0' allowed)
// @param length   the length of the data
//
// @return the object
//

- (DCRC32 *) init :(const unsigned char *) data :(unsigned long) length
{
  [self init];

  [self update :data :length];

  return self;
}


//// Update methods

//
// Update the object with a c-string. Repeated calls can be compared
// to a single call in which the strings are concatted
//
// @param cstring  the c-string to be feeded to crc32
//
// @return the object
//

- (DCRC32 *) update :(const char *) cstring
{
  if ((cstring != NULL) && (*cstring != EOS))
  {
    while (*cstring != EOS)
    {
      _crc32 = (_crc32 >> 8) ^ _table[ (_crc32 ^ *cstring++) & 0xFF ];
    }
  }

  return self;
}

//
// Update the object with data. Repeated calls can be compared
// to a single call in which the strings are concatted
//
// @param data     the data to be feeded to md5
// @param length   the length of the data
//
// @return the object
//

- (DCRC32 *) update :(const unsigned char *) data :(unsigned long) length
{
  while (length > 0)
  {
    _crc32 = (_crc32 >> 8) ^ _table[ (_crc32 ^ *data++) & 0xFF ];
    
    length--;
  }

  return self;
}


//// Result methods

//
// Return the (current) result of all data passed to the object. 
//
// @return the crc32 value
//

- (unsigned long) crc32
{
  return (unsigned long)(_crc32 ^ 0xFFFFFFFF);
}


@end

/*===========================================================================*/

